﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PJ.Framework.Common;

namespace PJ.Data
{
    /// <summary>
    /// ObjectWCFProvider : WCF Server provider.
    ///         Calls inner service that uses interface return objects and converts them to concrete WCF data contracts
    /// </summary>
    /// <typeparam name="TObjectData">Concrete class of served objects. WCF does not support interfaces or abstract class.</typeparam>
    /// <typeparam name="TIObjectProvider">Inner provider Interface</typeparam>
    public abstract class ObjectWCFProvider<TObjectData> : IObjectProvider<TObjectData>
        where TObjectData : BaseObjectData, IObjectData, new()
    {
        #region Constructors

        protected ObjectWCFProvider(IObjectProvider provider)
        {
            if (provider == null)
                throw new ArgumentNullException("provider");
            _Provider = provider;
        }

        #endregion

        #region Interface implementation
        /// <summary>
        /// Gets the data object from the data source
        /// </summary>
        /// <param name="globalId">Object global id</param>
        /// <returns>The data object if found or throws an exception</returns>
        public  TObjectData GetData(string globalId)
        {
            return ToContract(Provider.GetData(globalId));
        }

        /// <summary>
        /// Gets the data object using cache storage first, if not found in cache gets the data from the provider.
        /// </summary>
        /// <param name="globalId">Object global id</param>
        /// <returns>The data object if found or throws an exception</returns>
        public TObjectData CachedGet(string globalId)
        {
            return ToContract(Provider.CachedGet(globalId));
        }

        /// <summary>
        /// Finds the data object from the data source
        /// </summary>
        /// <param name="globalId">Object global id</param>
        /// <returns>The data object if found or returns null</returns>
        public TObjectData Find(string globalId)
        {
            return ToContract(Provider.Find(globalId));
        }

        /// <summary>
        /// Finds the data object using cache storage first, if not found in cache finds the data from the provider.
        /// </summary>
        /// <param name="globalId">Object global id</param>
        /// <returns>The data object if found or returns null</returns>
        public TObjectData CachedFind(string globalId)
        {
            return ToContract(Provider.CachedFind(globalId));
        }

        /// <summary>
        /// Persists the data object in the data source
        /// </summary>
        /// <param name="data">Object to persist</param>
        public void Persist(TObjectData data)
        {
            Provider.Persist(data);
        }

        /// <summary>
        /// Persists the data object in the data source and reloads it.
        /// </summary>
        /// <param name="data">Object to persist</param>
        /// <returns>persisted data</returns>
        public TObjectData PersistAndGet(TObjectData data)
        {
            return ToContract(Provider.PersistAndGet(data));
        }

        /// <summary>
        /// Checks if the data object exists in the data source
        /// </summary>
        /// <param name="globalId">Object global id</param>
        /// <returns>true if found in data source else false</returns>
        public bool Exist(string globalId)
        {
            return Provider.Exist(globalId);
        }

        /// <summary>
        /// Removes the data object from the data source
        /// </summary>
        /// <param name="globalId">Object global id</param>
        public void Delete(string globalId)
        {
            Provider.Delete(globalId);
        }


        /// <summary>
        /// Creates a new instance of the concrete class
        /// </summary>
        /// <returns>The data object if found or throws an exception</returns>
        public TObjectData CreateNewItem()
        {
            return new TObjectData();
        }


        #endregion

        #region Interface override
        /// <summary>
        /// Get : Gets the data object from the data source
        /// </summary>
        /// <param name="globalId">Object global id</param>
        /// <returns>The data object if found or throws an exception</returns>
        IObjectData IObjectProvider.GetData(string globalId)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// CachedGet : Gets the data object using cache storage first, if not found in cache gets the data from the provider.
        /// </summary>
        /// <param name="globalId">Object global id</param>
        /// <returns>The data object if found or throws an exception</returns>
        IObjectData IObjectProvider.CachedGet(string globalId)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Find : Finds the data object from the data source
        /// </summary>
        /// <param name="globalId">Object global id</param>
        /// <returns>The data object if found or returns null</returns>
        IObjectData IObjectProvider.Find(string globalId)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// CachedFind : Finds the data object using cache storage first, if not found in cache finds the data from the provider.
        /// </summary>
        /// <param name="globalId">Object global id</param>
        /// <returns>The data object if found or returns null</returns>
        IObjectData IObjectProvider.CachedFind(string globalId)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Persists the data object and reloads it
        /// </summary>
        /// <param name="data">Object to persist</param>
        /// <returns>persisted data</returns>
        IObjectData IObjectProvider.PersistAndGet(IObjectData data)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Set : Persists the data object in the data source
        /// </summary>
        /// <param name="data">Object to persist</param>
        void IObjectProvider.Persist(IObjectData data)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// CreateNewItem : Creates a new instance of the concrete class
        /// </summary>
        /// <returns>The data object if found or throws an exception</returns>
        IObjectData IObjectProvider.CreateNewItem()
        {
            return CreateNewItem();
        }



        #endregion

        #region Public
        #endregion

        #region Protected

        protected TObjectData ToContract(IObjectData data)
        {
            if (data == null)
                return null;
            TObjectData temp = data as TObjectData;
            if (temp == null)
                return CreateNewItem(data);
            else
                return temp;
        }
        protected TObjectData CreateNewItem(IObjectData data)
        {
            return (TObjectData)CreateNewItem().Init(data);
        }

        protected IObjectProvider Provider
        {
            get
            {
                if (_Provider == null)
                    throw new ArgumentNullException();
                return _Provider;
            }
        }


        #endregion

        #region Private


        #endregion

        #region Fields

        protected readonly IObjectProvider _Provider;
        
        #endregion
    }
}
